#include <stdio.h>
#include <stdlib.h>
#include "myhash.h"

#define TABLE_SIZE 	12
// #define LOAD_FACTOR 10	//每个unit应该均衡，但暂时不考虑
#define myhash(key) (key%TABLE_SIZE)	//哈希策略：取模

// 哈希策略可以改善 & 没有扩容机制 
// 想要改善和提升性能，可以去看uthash源码和JAVA中的Hashmap机制。


typedef struct hash_node {
	hash_msg_t *datafield;	//保存用户数据域的映射，必包含键值
	struct hash_node *next;
} hash_node_t;

// hash_unit管理单元
// uid对应在table中位置，也即是键值哈希后的返回值
// count：单元中的节点（用户）个数
typedef struct hash_unit {
	int uid;		// 0 ~ TABLE_SIZE-1
	int count;
	struct hash_node *head;
	struct hash_node *tail;
} hash_unit_t;

static hash_unit_t *ghash_table[TABLE_SIZE];	//哈希表统管全局，哈希单元统管哈希节点


static hash_unit_t *create_hash_unit(int uid) {
	hash_unit_t *unit = malloc(sizeof(*unit));
	unit->uid = uid;
	unit->count = 0;
	unit->head = NULL;
	unit->tail = NULL;
	return unit;
}

void hash_table_init() {
	for (int i = 0; i < TABLE_SIZE; i++) {
		ghash_table[i] = create_hash_unit(i);
	}
}

// 用户应该可以自定义数据域，添加哈希节点操作由模块完成，且不能随数据域变化而更改
// 用户提供数据，模块根据数据创建节点，但！又不能改变模块的数据结构；指针？
void hash_add(int key, hash_msg_t *dataptr) {
	hash_node_t *temp = malloc(sizeof(*temp));
	temp->datafield = dataptr;
	temp->next = NULL;

	hash_unit_t *unit = ghash_table[myhash(key)];
	if (unit->count == 0) {
		unit->head = temp;
		unit->tail = temp;
	} else {
		unit->tail->next = temp;
		unit->tail = temp;
	}
	unit->count++;
}

// *res是实参，为NULL时表示没有该节点
void hash_find(int key, hash_msg_t **res) {
	hash_unit_t *unit = ghash_table[myhash(key)];
	if (unit->count == 0) {
		*res = NULL;
		// printf("find failed, unit %d is empty.\n", myhash(key));
	} else {
		hash_node_t *prev, *cur;
		prev = cur = unit->head;
		while (cur && cur->datafield->key != key) {
			prev = cur;
			cur = cur->next;
		}
		*res = (cur != NULL)? cur->datafield:NULL;
	}
}

void hash_del(int key) {
	hash_unit_t *unit = ghash_table[myhash(key)];
	if (unit->count == 0) {
		printf("Delete failed, unit %d is empty.\n", myhash(key));
	} else {
		hash_node_t *prev, *cur;
		prev = cur = unit->head;
		while (cur && cur->datafield->key != key) {
			prev = cur;
			cur = cur->next;
		}
		if (cur != NULL) {		// 键值对应节点存在
			// 调整指针
			if (prev == cur) {	//节点是head
				unit->head = cur->next;
			} else {	
				prev->next = cur->next;
			}

			// 释放内存
			free(cur->datafield);
			free(cur);
			unit->count--;
		} else {	//没找到键值对应的节点
			printf("Not found %d user in unit.\n", key);
		}
	}
}

static void hash_unit_destroy(int uid) {
	hash_unit_t *unit = ghash_table[uid];
	hash_node_t *temp, *del = unit->head;
	while (del) {
		temp = del->next;
		free(del);
		del = temp;
	}
	free(unit);
}

void hash_table_destroy() {
	for (int i = 0; i < TABLE_SIZE; i++) {
		hash_unit_destroy(i);
		ghash_table[i] = NULL;
	}
}